# coding: UTF-8
# @Date    ：2024/10/14 18:23 
# @File    : demo_1.py
# :Author:  fum
import json
import os
import threading
from typing import List

import psutil
from fastapi import Depends
from pydantic import BaseModel
from sqlalchemy import text, Connection, select, and_
from sqlalchemy.orm import Session

from . import api
from .. import logger
from ...configs import CONFIG, ConfigManager
from ...middleware import box
from ...models.system import User


# 定义内存模型
class Memory(BaseModel):
    description: str = "内存信息描述"
    total: str = "总内存"
    used: str = "已用内存"
    usage: str = "内存使用率"


# 定义磁盘模型
class Disk(BaseModel):
    description: str = "磁盘信息描述"
    total: str = "总磁盘空间"
    used: str = "已用磁盘空间"
    usage: str = "磁盘使用率"


# 定义进程模型
class Process(BaseModel):
    pid: int = 0
    name: str = "进程名称"
    num_threads: int = 0


# 定义系统信息响应模型
class SystemInfoResponse(BaseModel):
    memory: Memory
    disk: Disk
    processes: List[Process]


@api.get('/')
def root():
    """返回系统内存、磁盘存储和进程/线程信息及描述。"""
    # 获取系统内存信息
    memory_info = psutil.virtual_memory()
    total_memory = round(memory_info.total / (1024 ** 3), 2)
    used_memory = round(memory_info.used / (1024 ** 3), 2)
    memory_usage = round(memory_info.percent, 2)

    # 获取磁盘存储信息
    disk_info = psutil.disk_usage('/')
    total_disk = round(disk_info.total / (1024 ** 3), 2)
    used_disk = round(disk_info.used / (1024 ** 3), 2)
    disk_usage = round(disk_info.percent, 2)

    # 获取进程和线程信息
    process_info = []
    for proc in psutil.process_iter(['pid', 'name', 'num_threads']):
        process_info.append({
            'pid': proc.info['pid'],
            'name': proc.info['name'],
            'num_threads': proc.info['num_threads']
        })

    # 构造返回结果
    response = {
        'memory': {
            'description': '总内存、已用内存和使用率（GB）',
            'total': f"{total_memory} GB",
            'used': f"{used_memory} GB",
            'usage': f"{memory_usage}%"
        },
        'disk': {
            'description': '总磁盘空间、已用磁盘空间和使用率（GB）',
            'total': f"{total_disk} GB",
            'used': f"{used_disk} GB",
            'usage': f"{disk_usage}%"
        },
        'processes': process_info
    }
    logger.info(response)
    return response


@api.get("/health")
def health():
    return json.dumps({"pid": os.getpid(), "status": "ok", "version": CONFIG.get("version")})


@api.get("/threads")
def threads():
    num_threads = threading.active_count()
    threads = threading.enumerate()

    thread_list = []
    for thread in threads:
        thread_name = thread.name
        thread_id = thread.ident
        is_alive = thread.is_alive()

        thread_list.append(
            {
                "name": thread_name,
                "id": thread_id,
                "is_alive": is_alive,
            }
        )
    return {
        "pid": os.getpid(),
        "thread_num": num_threads,
        "threads": thread_list,
    }


@api.get("/db-pool-state")
def get():
    return CONFIG.get("SQLALCHEMY_ENGINE_OPTIONS")


@api.get("/config")
async def read_singleton(config_manager: ConfigManager = Depends(lambda: box.config())):
    return config_manager.get_config()


@api.get("/VARIABLES")
def VARIABLES() -> list:
    """事务级别"""
    db_manager = box.db_manager()
    with db_manager.get_db_connection() as connection:  # type: Connection
        sql = text("SHOW VARIABLES LIKE 'transaction_isolation';")
        result = connection.execute(sql).first()
        return result


@api.get("/max_connections")
def max_connections() -> list:
    """数据库最大连接数"""
    db_manager = box.db_manager()
    with db_manager.get_db_connection() as connection:  # type: Connection
        sql = text("SHOW VARIABLES LIKE 'max_connections';")
        result = connection.execute(sql).first()
        return result


@api.get("/pool")
def pool() -> list:
    db_manager = box.db_manager()
    with db_manager.get_db_session() as session:  # type: Session
        stmt = select(User.email).where(and_(User.id > 60000, User.id < 80000))
        res = session.execute(stmt).scalars().all()
        return res
